/*********************************************************************************
 *      Copyright:  (C) 2025 YANG Studio
 *                  All rights reserved.
 *
 *       Filename:  esp8266.c
 *    Description:  This file 
 *                 
 *        Version:  1.0.0(27/05/25)
 *         Author:  YANG JIAYU <yangjiayu@gmail.com>
 *      ChangeLog:  1, Release initial version on "27/05/25 18:57:42"
 *                 
 ********************************************************************************/
#include "./BSP/ESP8266/esp8266.h"      // 包含ESP8266驱动头文件
#include "./SYSTEM/usart/usart.h"        // 包含串口通信头文件
#include "./SYSTEM/delay/delay.h"        // 包含延时函数头文件
#include "./BSP/LED/led.h"              // 包含LED驱动头文件
#include <string.h>                     // 包含字符串处理库

/* ESP8266接收缓冲区定义 */
#define ESP8266_RX_BUF_SIZE  256         // 接收缓冲区大小
static uint8_t esp8266_rx_buf[ESP8266_RX_BUF_SIZE];  // 接收缓冲区数组

/**
 * @brief       ESP8266初始化函数(含硬件复位和AT命令初始化)
 * @retval      0:初始化成功  1:初始化失败
 */
uint8_t ESP8266_Init(void) {
    uint8_t retry = 3;                  // 重试次数
    
    // 硬件复位注释(默认注释掉，如需使用请取消注释)
    // HAL_GPIO_WritePin(ESP8266_RST_GPIO_Port, ESP8266_RST_Pin, GPIO_PIN_RESET);  // 拉低复位引脚
    // delay_ms(200);                                                              // 保持低电平200ms
    // HAL_GPIO_WritePin(ESP8266_RST_GPIO_Port, ESP8266_RST_Pin, GPIO_PIN_SET);    // 拉高复位引脚
    // delay_ms(1000);                                                             // 等待1000ms稳定
    
    // 发送AT命令进行初始化
    while (retry--) {
        if (ESP8266_Cmd("AT", "OK", 500)) {       // 发送AT测试命令
            ESP8266_Cmd("AT+CWMODE=1", "OK", 500); // 设置为STA模式(客户端模式)
            ESP8266_Cmd("AT+CIOBAUD=115200", "OK", 500); // 设置通信波特率
            ESP8266_Cmd("AT+ATE0", "OK", 500);     // 关闭回显功能
            return 0;                             // 初始化成功
        }
        delay_ms(500);                            // 延时后重试
    }
    return 1;                                     // 初始化失败
}

/**
 * @brief       连接WiFi网络(STA模式)
 * @param       ssid: WiFi名称
 * @param       pwd: WiFi密码
 * @retval      0:连接失败  1:连接成功
 */
uint8_t ESP8266_ConnectWiFi(char *ssid, char *pwd) {
    char cmd[128];                                // 命令缓冲区
    sprintf(cmd, "AT+CWJAP=\"%s\",\"%s\"", ssid, pwd); // 生成连接WiFi命令
    
    // 最多重试3次
    for (uint8_t i = 0; i < 3; i++) {
        if (ESP8266_Cmd(cmd, "GOT IP", 15000)) { // 等待获取IP地址
            return 1;                             // 连接成功
        }
        delay_ms(1000);                            // 延时后重试
    }
    return 0;                                     // 连接失败
}

/**
 * @brief       连接TCP/UDP服务器
 * @param       type: 连接类型("TCP"或"UDP")
 * @param       ip: 服务器IP地址
 * @param       port: 服务器端口号
 * @retval      0:连接失败  1:连接成功
 */
uint8_t ESP8266_ConnectServer(char *type, char *ip, uint16_t port) {
    char cmd[128];                                // 命令缓冲区
    sprintf(cmd, "AT+CIPSTART=\"%s\",\"%s\",%d", type, ip, port); // 生成连接服务器命令
    
    return ESP8266_Cmd(cmd, "OK", 5000);          // 发送命令并等待响应
}

/**
 * @brief       向服务器发送数据(支持透传模式)
 * @param       data: 发送数据指针(需为uint8_t类型)
 * @param       len: 数据长度(最大2048字节)
 * @retval      0:发送失败  1:发送成功
 */
uint8_t ESP8266_SendData(uint8_t *data, uint16_t len) {
    if (len == 0 || len > 2048) return 1; // 检查数据长度有效性
    
    char cmd[20];                           // 命令缓冲区
    sprintf(cmd, "AT+CIPSEND=%d", len);     // 生成发送数据长度命令
    
    if (!ESP8266_Cmd(cmd, ">", 1000)) return 1; // 等待进入数据发送状态
    
    // 通过HAL库发送数据(注意：需根据实际使用的串口修改句柄)
    if (HAL_UART_Transmit(&g_uart1_handle, data, len, 2000) != HAL_OK) {
        return 1;                             // 数据发送失败
    }
    
    return ESP8266_Cmd("", "SEND OK", 3000); // 等待数据发送完成确认
}

/**
 * @brief       检查服务器连接状态
 * @retval      1:已连接  0:未连接
 */
uint8_t ESP8266_CheckStatus(void) {
    return ESP8266_Cmd("AT+CIPSTATUS", "CONNECTED", 500); // 检查连接状态
}

/**
 * @brief       处理ESP8266接收数据(解析命令)
 */
void ESP8266_Process(void) {
    uint16_t len = usart_get_rx_data(esp8266_rx_buf, ESP8266_RX_BUF_SIZE); // 获取接收数据长度
    
    if (len > 0) {
        esp8266_rx_buf[len] = '\0'; // 为接收数据添加字符串结束符
        
        // 调试输出：打印接收到的数据
        printf("ESP8266 Rx: %s\r\n", esp8266_rx_buf);
        
        // 示例：解析远程控制命令(以LED控制为例)
        if (strstr((char *)esp8266_rx_buf, "LED=ON") != NULL) {
            LED0(0); // 点亮LED
        } else if (strstr((char *)esp8266_rx_buf, "LED=OFF") != NULL) {
            LED0(1); // 熄灭LED
        }
    }
}

/**
 * @brief       发送AT命令并等待响应(核心通信函数)
 * @param       cmd: AT命令(若为NULL则表示仅等待响应)
 * @param       resp: 期望的响应字符串
 * @param       timeout: 超时时间(毫秒)
 * @retval      1:收到期望响应  0:超时未收到响应
 */
uint8_t ESP8266_Cmd(char *cmd, char *resp, uint32_t timeout) {
    uint32_t start_time = HAL_GetTick();       // 记录开始时间
    uint8_t result = 0;                        // 结果标志
    
    // 清空接收缓冲区
    memset(esp8266_rx_buf, 0, ESP8266_RX_BUF_SIZE);
    
    // 发送AT命令(若cmd非空且非空字符串)
    if (cmd != NULL && *cmd != '\0') {
        HAL_UART_Transmit(&g_uart1_handle, (uint8_t *)cmd, strlen(cmd), 1000); // 发送命令
        HAL_UART_Transmit(&g_uart1_handle, (uint8_t *)"\r\n", 2, 1000);       // 发送回车换行
    }
    
    // 等待响应
    while (HAL_GetTick() - start_time < timeout) {
        uint16_t len = usart_get_rx_data(esp8266_rx_buf, ESP8266_RX_BUF_SIZE); // 获取接收数据
        
        if (len > 0) {
            // 检查是否收到期望响应(若resp为NULL则认为只要收到数据即成功)
            if (resp == NULL || strstr((char *)esp8266_rx_buf, resp) != NULL) {
                result = 1;        // 收到期望响应
                break;             // 跳出等待循环
            }
        }
        delay_ms(10);              // 短延时释放CPU
    }
    return result;                 // 返回响应结果
}

